<template>
	<view v-if="loaded" class="row full-width tab-bar">
		<view
			:class="['row', 'tab-label', tabClass(index), dragClass(index), displayClass(index)]" 
			v-for="(t, index) in tabList" 
			:key="t.tabId" 
			:id="`defect-tab-${t.tabId}`"
			@touchcancel="handleDragCancel"
			@touchstart="handleDragStart($event, t, index)"
			@touchend="handleDragEnd($event, t, index)"
			@touchmove="handleDragMove($event, t, index)">
			<text>{{ t.tabName }}</text>
			<uni-icons v-if="clearable" class="tab-icon" type="closeempty" size="10" color="#FFFFFF"></uni-icons>
		</view>
		<view 
			v-if="dragTab"
			ref="dragTag"
			:class="['row', 'tab-label', 'tab-label-drag']"
			:style="{left: dragTabLeft+'px', top: dragTabTop+'px'}">
			<text>{{ dragTab.tabName }}</text>
			<uni-icons v-if="clearable" class="tab-icon" type="closeempty" size="10" color="#FFFFFF"></uni-icons>
		</view>
	</view>
</template>

<script>
	import { getTabs, updateSortOfTabs } from '@/api/system/DefectTabs';
	import {DEFECT_TAB_BAR_TYPE} from '@/utils/defect.js'
	
	// 全局标签顺序改变事件名
	const EVENT_GLOBAL_SORT_CHANGE = 'global-sort-change';
	export default {
		name: 'DefectTabBar',
		model: {
			prop: 'value',
			event: 'input'
		},
		data() {
			return {
				currentTabIndex: 0,
				tabList: [],
				tabRectMap: new Map(),
				dragTabIndex: -1,
				dragTab: null,
				dragTabLeft: 0,
				dragTabTop: 0,
				dragTabOffsetLeft: 0,
				dragTabOffsetTop: 0,
				isDrag: false,
				insertTabIndex: -1
			}
		},
		props: {
			value: {
				type: Number,
				default: 0
			},
			tabs: {
				type: Array,
				default: ()=>[]
			},
			clearable: {
				type: Boolean,
				default: true
			},
			type: {
				type: String,
				default: DEFECT_TAB_BAR_TYPE.LIST,
				validator: (value) => Object.values(DEFECT_TAB_BAR_TYPE).includes(value)
			},
		},
		created() {
			this.tabList = [...this.tabs];
			this.currentTabIndex = this.value;
			uni.$on(EVENT_GLOBAL_SORT_CHANGE, data=>{
				this.$emit('sort-change', data)
			})
		},
		computed: {
			/** 是否加载完成  */
			loaded() {
				return (this.$i18n && this.$i18n.locale)?true:false;
			},
			/** 标签样式 */
			tabClass() {
				return function(index) {
					if(index===this.currentTabIndex && this.type===DEFECT_TAB_BAR_TYPE.RADIO) {
						return 'tab-label-action';
					} else {
						return 'tab-label-' + (this.type||DEFECT_TAB_BAR_TYPE.LIST);
					}
				}
			},
			/** 拖动的样式 */
			dragClass() {
				return function(index) {
					if(this.isDrag) {
						if(index === this.insertTabIndex) {
							if(index>-1 && index<this.tabList.length) {
								return 'tab-label-drag-left';
							} 
						} else if(index === this.tabList.length-1 && this.insertTabIndex===this.tabList.length) {
							return 'tab-label-drag-right';
						}
					}
					return '';
				}
			},
			displayClass() {
				return function(index) {
					if(this.isDrag && index === this.dragTabIndex) {
						return 'tab-label-display-none';
					} 
					return '';
				}
			},
		},
		watch: {
			tabs: function(n) {
				if(n) {
					this.tabList = [...n];
				}
			}
		},
		methods: {
			/** 处理标签拖动开始 */
			handleDragStart(e, tab, index) {
				if(this.type !== DEFECT_TAB_BAR_TYPE.LIST) return;
				const self = this;
				this.dragTabOffsetLeft = 0;
				this.dragTabOffsetTop = 0;
				const query = uni.createSelectorQuery().in(this);
				query.select('#'+e.currentTarget.id).boundingClientRect(data => {
				    self.dragTabOffsetLeft = e.touches[0].clientX - data.left;
				    self.dragTabOffsetTop = e.touches[0].clientY - data.top;
				}).exec();
				this.insertTabIndex = index;
				this.dragTabIndex = index;
				this.tabRectMap.clear();
				e.preventDefault();
			},
			/** 处理标签拖动结束 */
			handleDragEnd(e, tab, index) {
				// if(this.type !== DEFECT_TAB_BAR_TYPE.LIST) return;
				if(this.isDrag) {
					if(this.dragTabIndex>=0 && this.dragTab && this.insertTabIndex>=0) {
						// this.tabList.splice(this.insertTabIndex,0,this.dragTab);
						this.dragTabIndex = -1;
						this.insertTabIndex = -1;
						this.dragTab = null;
						this.updateTabSort();
					}
					this.isDrag = false;
				} else {
					this.currentTabIndex = index;
					this.$emit('input', index, tab);
				}
				e.preventDefault();
			},
			handleDragCancel(e) {
				console.log('cancel', e)
			},
			/** 处理标签拖动 */
			handleDragMove(e) {
				if(this.type !== DEFECT_TAB_BAR_TYPE.LIST) return;
				const self = this;
				if(this.isDrag===false) {
					this.isDrag = true;
					this.dragTab = this.tabList[this.dragTabIndex];
					// this.tabList.splice(this.dragTabIndex, 1);
					// 遍历统计现有标签所在区域
					this.$nextTick(()=>{
						for(let i = 0;i<self.tabList.length;i++) {
							const id = self.getTabElementId(self.tabList[i]);
							const tab = self.$refs[id];
							const query = uni.createSelectorQuery().in(self);
							query.select('#'+id).boundingClientRect(data => {
								self.tabRectMap.set(id, data);
							}).exec();
						}
					})
				}
				// 计算当前鼠标所在标签，并显示ui效果
				if(e.changedTouches && e.changedTouches.length>0) {
					const { pageX, pageY } = e.changedTouches[0];
					// 设置被拖拽标签的坐标
					this.dragTabLeft = pageX - this.dragTabOffsetLeft;
					this.dragTabTop = pageY - this.dragTabOffsetTop;
					// 遍历所有标签，当鼠标在某一标签范围内，显示插入效果
					for(let i = 0;i<this.tabList.length;i++) {
						const id = this.getTabElementId(this.tabList[i]);
						if(this.tabRectMap.has(id)) {
							// 鼠标位置
							const point = {x:pageX, y: pageY};
							// 当前标签区域
							const tabRect = this.tabRectMap.get(id);
							// 计算拖动后，标签要插入的索引位置
							if(this.isPointInRectLeft(point, tabRect)) {
								this.insertTabIndex = i;
								break;
							} else if(this.isPointInRectRight(point, tabRect)) {
								this.insertTabIndex = i+1;
								break;
							}
						}
					}
				}
				e.preventDefault();
			},
			/** 获取标签Dom元素ID */
			getTabElementId(tab) {
				return 'defect-tab-'+tab.tabId;
			},
			/** 鼠标点是否在指定区域左侧 */
			isPointInRectLeft(point, rect) {
				return point.x >= rect.left && 
			         point.x <= rect.right - rect.width/2 && 
			         point.y >= rect.top && 
			         point.y <= rect.bottom;
			},
			/** 鼠标点是否在指定区域右侧 */
			isPointInRectRight(point, rect) {
				return point.x >= rect.left + rect.width/2 && 
			         point.x <= rect.right && 
			         point.y >= rect.top && 
			         point.y <= rect.bottom;
			},
			/** 更新标签顺序 */
			updateTabSort() {
				const body = this.tabList.map((t,index)=>{
					return {
						tabId: t.tabId,
						tabSort: 999 - index
					}
				});
				updateSortOfTabs(body).then(res=>{
					uni.$emit(EVENT_GLOBAL_SORT_CHANGE, body);
				});
			}
		}
	}
</script>

<style lang="scss" scoped>
	.tab-bar {
		flex-wrap: wrap;
		.tab-label {
			padding: 5rpx 20rpx;
			border-radius: 5rpx;
			display: inline-flex;
			align-items: center;
			gap: 5rpx;
			> .tab-icon {
				padding-bottom: 5rpx;
			}
		}
		.tab-label-list {
			color: $uni-text-color-inverse;
			background-color: #007AFF;
		}
		.tab-label-radio {
			color: $uni-text-color;
			background-color: $uni-bg-color-grey;
			border: 2rpx solid $uni-border-color;
		}
		.tab-label-action {
			color: $uni-text-color-inverse;
			background-color: #007AFF;
		}
		.tab-label-drag {
			position: fixed;
			flex-shrink: 0;
			color: $uni-text-color-inverse;
			background-color: #77baff;
			z-index: 999;
		}
		.tab-label-drag-left::before {
			content: ' ';
			height: 100%;
			border-left: 4rpx solid #8f939c;
			left: -28rpx;
			position: relative;
		}
		.tab-label-drag-right::after {
			content: ' ';
			height: 100%;
			border-right: 4rpx solid #8f939c;
			right: -28rpx;
			position: relative;
		}
		.tab-label-display-none {
			display: none;
		}
	}
</style>